package cn.barudisshu.route;

import cn.barudisshu.annotations.API;
import cn.barudisshu.annotations.GET;
import cn.barudisshu.annotations.POST;
import cn.barudisshu.http.HttpMethod;
import cn.barudisshu.http.Resource;
import cn.barudisshu.loaders.ResourceLoader;
import cn.barudisshu.util.CaseInsensitiveMap;
import cn.barudisshu.util.analysis.ParamAttribute;
import cn.barudisshu.util.analysis.ParamNamesScaner;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @author galudisu
 */
public final class RouteBuilder {

    private ResourceLoader resourceLoader;

    private Map<String, Map<String, Set<Route>>> routesMap = new CaseInsensitiveMap<>();

    public RouteBuilder(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public void build(){
        for (Class<? extends Resource> resource : resourceLoader.getResources()) {

            String apiPath = getApi(resource);
            //自己的方法
            Method[] methods;
            //获取参数
            Map<String, ParamAttribute> classParamNames = ParamNamesScaner.getParamNames(resource);
            if (Modifier.isAbstract(resource.getSuperclass().getModifiers())) {
                methods = resource.getMethods();
            } else {
                methods = resource.getDeclaredMethods();
            }
            //遍历方法看是不是 restful api
            for (Method method : methods) {

                // GET 请求
                GET get = method.getAnnotation(GET.class);
                if (get != null) {
                    addRoute(HttpMethod.GET, apiPath, get.value(), resource, classParamNames, method);

                    continue;
                }
                // POST 请求
                POST post = method.getAnnotation(POST.class);
                if (post != null) {
                    addRoute(HttpMethod.POST, apiPath, get.value(), resource, classParamNames, method);
                    continue;
                }

                // todo: 其它请求
            }
        }
    }

    // 添加Route对象到集合 routesMap中
    private void addRoute(String httpMethod, String apiPath, String methodPath, Class<? extends Resource> resourceClass,Map<String, ParamAttribute> classParamNames, Method method){
        String patternPath = getApi(apiPath, methodPath);
        Route route = new Route(resourceClass, ParamNamesScaner.getParamNames(method, classParamNames), httpMethod, patternPath, method);

        //资源的标志
        if (apiPath.contains("([^\\/]+)")) {
            throw new IllegalArgumentException("Api path could not contains pattern. Because this is a resource url.");
        }

        // todo: 写入到routesMap中
        if(routesMap.containsKey(httpMethod)){
            Map<String, Set<Route>> routesHttpMethodMap = routesMap.get(httpMethod);
            //url
            if(routesHttpMethodMap.containsKey(apiPath)){
                Set<Route> routes = routesHttpMethodMap.get(apiPath);

                // 判断重复
                for (Route r : routes) {
                    // todo: 若存在路由相同的，抛出 IllegalArgumentException
                }
                routesMap.get(httpMethod).get(apiPath).add(route);
            }else{
                routesMap.get(httpMethod).put(apiPath, newRouteDESCSet(route));
            }
        }else{
            routesMap.put(httpMethod, newRouteMap(apiPath, route));
        }
    }

    /**
     * 获取api部分
     *
     * @param resourceClazz resource class
     * @return url apiPath
     */
    private String getApi(Class<? extends Resource> resourceClazz) {
        API api;
        String apiPath = "";
        api = resourceClazz.getAnnotation(API.class);
        if (api != null) {
            apiPath = api.value();
            if (!apiPath.equals("")) {
                if (!apiPath.startsWith("/")) {
                    apiPath = "/" + apiPath;
                }
            }
        }
        Class<?> superClazz = resourceClazz.getSuperclass();
        if (Resource.class.isAssignableFrom(superClazz)) {
            apiPath = getApi((Class<? extends Resource>) superClazz) + apiPath;
        }
        return apiPath;
    }

    /**
     * 最终生成的apiPath
     *
     * @param apiPath
     * @param methodPath
     * @return
     */
    private String getApi(String apiPath, String methodPath) {
        if (!methodPath.equals("")) {
            if (!methodPath.startsWith("/")) {
                apiPath = apiPath + "/" + methodPath;
            } else {
                apiPath = apiPath + methodPath;
            }
        }
        return apiPath;
    }


    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }

    public Map<String, Map<String, Set<Route>>> getRoutesMap() {
        return Collections.unmodifiableMap(routesMap);
    }

    /**
     * 创建一个对key排序的map
     *
     * @param apiPath apiPath
     * @param route   route
     * @return map
     */
    public Map<String, Set<Route>> newRouteMap(final String apiPath, final Route route) {
        return new TreeMap<String, Set<Route>>((k1, k2) -> {
            int result = k2.length() - k1.length();
            if (result == 0) {
                return k1.compareTo(k2);
            }
            return result;
        }) {{
            put(apiPath, newRouteDESCSet(route));
        }};
    }

    /**
     * 创建一个倒排序的route
     *
     * @param route route
     * @return Set
     */
    public Set<Route> newRouteDESCSet(final Route route) {
        return new TreeSet<Route>(
                new Comparator<Route>() {
                    public int compare(Route a, Route b) {
                        // TODO: 2017/1/19 compare a & b's pattern and method
                        return 0;
                    }
                }) {{
            add(route);
        }};
    }

}
